/* Standard headers */
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <math.h>

#include "cw_trend_draw.h"
#include "CwTrend.h"
//#include "trenddb.h"

//-----------------------------------------------------------------------------
// установка шрифта
//-----------------------------------------------------------------------------
int cw_trend_set_font (int font_size)
{
    char Helvetica [MAX_FONT_TAG];

    if(PfGenerateFontName("Helvetica", 0, font_size, Helvetica) == NULL) {
        perror("Unable to find font");
        return -1;
    } else {
        PgSetFont (Helvetica);
    }
    return 0;
}

//-----------------------------------------------------------------------------
// прорисовка горизонтальной оси (время)
//-----------------------------------------------------------------------------
void cw_trend_draw_time_axe (PhPoint_t beg_p, PhPoint_t end_p, int n_horz, 
							time_t t_now, time_t t_end, double t_ptr)
{
	PhPoint_t	p;
	PhRect_t	r;
    int			i;
    char		str [32];
    time_t		time;

	PgSetFillColor	(Pg_GREEN);
	PgSetStrokeColor (Pg_BLACK);

	cw_trend_set_font (8);

	PgDrawLine (&beg_p, &end_p);
	p.y = 0;
	p.x = n_horz;
	r.ul = beg_p; 		r.ul.y -= 4;
	r.lr = end_p; 		r.lr.y += 4;
	PgDrawGrid (&r, &p);
	p.x *= 10;
	r.ul.y += 3;	r.lr.y -= 2;
	PgDrawGrid (&r, &p);

    PgSetTextColor (Pg_BLACK);

	for (i = 0; i <= n_horz; i++) {
		p.x = beg_p.x + i * (end_p.x - beg_p.x)/n_horz;
		p.y = beg_p.y + 7;
		time = t_now - (t_now - t_end)*i/n_horz;
		strftime (str, 32, "%T", localtime (&time)); 
		PgDrawText (str, strlen (str), &p, Pg_TEXT_CENTER |Pg_TEXT_TOP);	
		p.y = beg_p.y + 20;
		strftime (str, 32, "%d-%m-%Y", localtime (&time)); 
		PgDrawText (str, strlen (str), &p, Pg_TEXT_CENTER |Pg_TEXT_TOP);	
	}

	if ((t_ptr < t_now)&& (t_ptr > t_end)) {
		p.x = beg_p.x + (t_now - t_ptr) * (end_p.x - beg_p.x)/(t_now - t_end);
		p.y = beg_p.y + 5;
		PgSetFillColor (Pg_WHITE);
		r.ul.x = p.x - 30;
		r.ul.y = p.y; 
		r.lr.x = p.x + 30;
		r.lr.y = p.y + 28; 
		PgDrawRect (&r, Pg_DRAW_FILL_STROKE);

		time = t_ptr;
		p.y = beg_p.y + 7;
		strftime (str, 32, "%T", localtime (&time)); 
		PgDrawText (str, strlen (str), &p, Pg_TEXT_CENTER |Pg_TEXT_TOP);	
		p.y = beg_p.y + 20;
		strftime (str, 32, "%d-%m-%Y", localtime (&time)); 
		PgDrawText (str, strlen (str), &p, Pg_TEXT_CENTER |Pg_TEXT_TOP);	
	}
}


//-----------------------------------------------------------------------------
// прорисовка вертикальных осей
// n_axis - кол-во осей
// n_vert - кол-во делений 
//-----------------------------------------------------------------------------
void cw_trend_draw_axis (CwTrendWidget_t *trend, PhRect_t rect, double *cur_value, int printing)
{
	PhPoint_t	p1, p2;
	PhPoint_t	p;
	PhRect_t	r;
	int			h_step, v_step;
	int 		i, j;
    char 		str [32];
    int 		vis_axis = 0;
    
    char		*label;
    char		*std_label = "NA";
    char		*ax_fmt;
    char		*std_ax_fmt = "%.1f";
	
	PgSetStrokeColor (Pg_BLACK);

	for (i = 0; i < trend->n_series; i++) {
		if ((trend->mask >> i)&1) {
			vis_axis ++;
		}
	}
	
	if (vis_axis == 0) return;
	
	h_step = (rect.lr.x - rect.ul.x)/vis_axis;
	v_step = (rect.lr.y - rect.ul.y+1)/trend->n_vert;
	p1.y = rect.ul.y;
	p1.x = rect.ul.x + h_step;
	p2.y = rect.lr.y;
	p2.x = p1.x;

	cw_trend_set_font (8);

	for (i = 0; i < trend->n_series; i++) {
		if (!((trend->mask >> i)&1)) continue;	

		PgSetStrokeColor (Pg_BLACK);
		PgDrawLine (&p1, &p2);

		p.x = 0;
		p.y = trend->n_vert;
		r.ul = p1; 		r.ul.x -= 4;
		r.lr = p2; 		r.lr.x += 4;
		PgDrawGrid (&r, &p);
		p.y *= 10;
		r.ul.x += 2;	r.lr.x -= 3;
		PgDrawGrid (&r, &p);

		r.ul.x = p1.x - h_step + 7;
		r.ul.y = p1.y + 10;
		r.lr.x = p1.x - 7;
		r.lr.y = p1.y + 50; 
	    PgSetTextColor (trend->color [i]);

	    if (trend->labels [i]) label = trend->labels [i];
		else label = std_label;
		if (trend->ax_fmt [i]) ax_fmt = trend->ax_fmt [i];
		else ax_fmt = std_ax_fmt;	    

		PgDrawMultiTextArea (label, strlen (label), 
									&r, Pg_TEXT_RIGHT, Pg_TEXT_RIGHT |Pg_TEXT_TOP, 0);

	    PgSetTextColor (Pg_BLACK);
		for (j = 0; j <= trend->n_vert; j++) {
			p.x = p1.x - 7;
			p.y = p1.y + j * (rect.lr.y - rect.ul.y)/trend->n_vert;
			sprintf (str, ax_fmt, trend->max_y [i] - ((float)j) * (trend->max_y [i] - trend->min_y [i])/((float)trend->n_vert)); 
			PgDrawText (str, strlen (str), &p, Pg_TEXT_RIGHT |Pg_TEXT_MIDDLE);	
		}

		if ((cur_value [i] >= trend->min_y [i]) && (cur_value [i] <= trend->max_y [i])) {
			PhPoint_t cp1, cp2;
			PgSetStrokeColor (trend->color [i]);
			PgSetStrokeWidth (4);
			cp1.x = p1.x - 3;
			cp1.y = p1.y + (trend->max_y [i] - cur_value [i])*(p2.y - p1.y)/(trend->max_y [i] - trend->min_y [i]);
			cp2.x = p1.x + 3;  
			cp2.y = cp1.y;
			PgDrawLine (&cp1, &cp2);
			
			PgSetStrokeWidth (1);
			PgSetFillColor (Pg_WHITE);
			r.ul.x = cp1.x - 35;
			r.ul.y = cp1.y - 6; 
			r.lr.x = cp1.x - 1;
			r.lr.y = cp1.y + 6; 
			PgDrawRect (&r, Pg_DRAW_FILL_STROKE);
			p.x = cp1.x - 17;
			p.y = cp1.y;

			sprintf (str, ax_fmt, cur_value [i]); 
			PgDrawText (str, strlen (str), &p, Pg_TEXT_CENTER |Pg_TEXT_MIDDLE);	
		}
		
		p1.x += h_step;
		p2.x = p1.x;
	}
}

//-----------------------------------------------------------------------------
// прорисовка вертикального курсора
//-----------------------------------------------------------------------------
void cw_trend_draw_cursor (CwTrendWidget_t *trend, PhRect_t rect, double *ptr_value)
{
	PhPoint_t	p1, p2;
	PhPoint_t	p;
	PhRect_t	r;
	int 		i;
    char 		str [32];
    int 		vis_axis = 0;

    char		*ax_fmt;
    char		*std_ax_fmt = "%.1f";
	
	PgSetStrokeColor (Pg_BLACK);
	
	for (i = 0; i < trend->n_series; i++) {
		if ((trend->mask >> i)&1) {
			vis_axis ++;
		}
	}
	if (vis_axis == 0) return;
	if ((trend->time_ptr > trend->time_end)||(trend->time_ptr < (trend->time_end - trend->time_win))) return;

	p1.y = rect.ul.y;
	p1.x = rect.ul.x + (trend->time_end - trend->time_ptr)*(rect.lr.x - rect.ul.x)/(trend->time_win);
	p2.y = rect.lr.y;
	p2.x = p1.x;
	
	PgSetStrokeColor (Pg_BLACK);
	PgDrawLine (&p1, &p2);

	cw_trend_set_font (8);
	PgSetTextColor (Pg_BLACK);

	for (i = 0; i < trend->n_series; i++) {
		if (!((trend->mask >> i)&1)) continue;	
		if ((ptr_value [i] >= trend->min_y [i]) && (ptr_value [i] <= trend->max_y [i])) {
			PhPoint_t cp1, cp2;
			PgSetStrokeColor (trend->color [i]);
			PgSetStrokeWidth (4);
			cp1.x = p1.x - 3;
			cp1.y = p1.y + (trend->max_y [i] - ptr_value [i])*(p2.y - p1.y)/(trend->max_y [i] - trend->min_y [i]);
			cp2.x = p1.x + 3;  
			cp2.y = cp1.y;
			PgDrawLine (&cp1, &cp2);
			
			PgSetStrokeWidth (1);
			PgSetFillColor (Pg_WHITE);
			r.ul.x = cp1.x - 35;
			r.ul.y = cp1.y - 6; 
			r.lr.x = cp1.x - 1;
			r.lr.y = cp1.y + 6; 
			PgDrawRect (&r, Pg_DRAW_FILL_STROKE);
			p.x = cp1.x - 17;
			p.y = cp1.y;

			if (trend->ax_fmt [i]) ax_fmt = trend->ax_fmt [i];
			else ax_fmt = std_ax_fmt;	    

			sprintf (str, ax_fmt, ptr_value [i]); 
			PgDrawText (str, strlen (str), &p, Pg_TEXT_CENTER |Pg_TEXT_MIDDLE);	
		}
	}
}

//-----------------------------------------------------------------------------
// прорисовка сетки
//-----------------------------------------------------------------------------
void cw_trend_draw_grid (PhRect_t rect, int n_x, int n_y, PgColor_t color)
{
	PhPoint_t p;

	PgSetStrokeDash ("\2", 1, 0x10000 );
	PgSetStrokeColor (color);

	p.x = n_x;	p.y = n_y;
	PgDrawGrid (&rect, &p);

	PgSetStrokeDash (NULL, 0, 0x10000 );
}

//-----------------------------------------------------------------------------
// 
//-----------------------------------------------------------------------------
void cw_trend_limit_buf (pt_t *pt, int npt, double t_beg, double t_end, double y_min, double y_max)
{
	int i;
	double t = t_end - t_beg;
	//double y = y_max - y_min;
	
	for (i= 0; i< npt; i++) {
		if (pt [i].t > t_end) pt [i].t = t_end + t;
		if (pt [i].t < t_beg) pt [i].t = t_beg - t;
		//if (pt [i].y > y_max) pt [i].y = y_max + y;		
		//if (pt [i].y < y_min) pt [i].y = y_min - y;
		//printf ("i= %d, t = %d, y = %d\n", i, pt [i].t, pt [i].y);
	}
}

//-----------------------------------------------------------------------------
// прорисовка тренда/графика по массиву точек вида series_t (time_t, data_t)
// (int) y = y_real * y_gain
// (int) t = t_real * t_gain 
// t_gain = 1 для секунд 
//-----------------------------------------------------------------------------
void cw_trend_draw_yt_trend (CwTrendWidget_t *trend, PhRect_t r, int n_ser, 
							int t_beg, int t_end, double period, double gap,
							double *plast_val, double *pptr_val) 
{
	const int max_nvalues = 500;

	double			t_scale;
	double			t_offs;
	double			y_scale;
	double			y_offs;

	int 			beg_found;    
	pt_t			*val;
	pt_t			*values;
	int				nvalues;
	int				ptr_found = 0;
	int				last_found = 0;
	pt_t			*prev_pt;
	
	int i;
	PhPoint_t *points, p1;

//	printf ("draw: n_ser = %d, *values = %p, nvalues = %d\n", n_ser, values, nvalues);

	*plast_val = 0;
	*pptr_val  = 0;

	PgSetStrokeColor (trend->color [n_ser]);
	PgSetStrokeWidth (1);

	t_scale = (double)(r.ul.x - r.lr.x)/fabs (t_end - t_beg);
	t_offs  = (double)(r.ul.x - t_end * t_scale);

	y_scale = (double)(r.ul.y - r.lr.y)/fabs (trend->max_y [n_ser] - trend->min_y [n_ser]);
	y_offs  = (double)(r.ul.y - trend->max_y [n_ser] * y_scale);

	nvalues = 0;
	values = NULL;
	for (i =0, beg_found =0; i< trend->data_buf [n_ser].nvalues; i++) {
		val = &trend->data_buf [n_ser].values [i]; 
//		printf ("t = %f; t_beg = %d; t_end = %d; nvalues = %d\n", val->t, t_beg, t_end, nvalues);
		if (!beg_found && (val->t >= (double) t_beg)) {
			if (i > 0) {
				values = &trend->data_buf [n_ser].values [i -1];
				nvalues = 2;
			} else {
				values = &trend->data_buf [n_ser].values [i];
				nvalues = 1;
			}
			beg_found = 1;
		}
		else if (beg_found) {
			nvalues ++;
			if (val->t > (double) t_end) {
				break;
			}
		}
	}
	if (nvalues == 0) return;
//	printf ("nvalues = %d; trend->nvalues = %d\n", nvalues, trend->data_buf [n_ser].nvalues);
//	printf ("t_beg = %d (%f); t_end = %d (%f)\n", t_beg, values [0].t, t_end, values [nvalues -1].t);
	
	if (values)
	{
		int j, k;
		p1.x = 0;
		p1.y = 0;

		points = calloc ((nvalues<max_nvalues)?nvalues:max_nvalues, sizeof (PhPoint_t));
		prev_pt = &values [0];
		for (i=0, j=0, k=0; (i-k)< nvalues; i++, j=i%max_nvalues) {
			
			if (!ptr_found) {
				if (values [i-k].t == trend->time_ptr) {
					*pptr_val = values [i-k].y;
					ptr_found = 1;	
				} 
				else if (values [i-k].t > trend->time_ptr) {
					if ((i-k-1) >= 0) {
						if (values [i-k-1].y < trend->time_ptr) {
							double x1 = values [i-k-1].t;
							double x2 = values [i-k].t;
							double y1 = values [i-k-1].y;
							double y2 = values [i-k].y;
							*pptr_val = y1 + (trend->time_ptr - x1)*(y2 - y1)/(x2 - x1);
							ptr_found = 1;	
						}						
					}
				}
			}
			if (!last_found) {
				if (values [i-k].t >= t_end) {
					*plast_val = prev_pt->y;
					last_found = 1;	
				}
				prev_pt = &values [i-k];
			}
			points [j].x = t_offs + t_scale * values [i-k].t;
			points [j].y = y_offs + y_scale * values [i-k].y /trend->scale [n_ser];
			if (j==(max_nvalues-1)) {
				PgDrawPolygon (points, max_nvalues, &p1, Pg_DRAW_STROKE);
				k++;
			}
		}				
		if (j!=0) {
			PgDrawPolygon (points, j, &p1, Pg_DRAW_STROKE);
		}
//		printf ("j = %d, i = %d, max_nvalues = %d\n", j, i, max_nvalues);
//		for (i =0; i<4; i++) printf ("points [%d].x = %d, y = %d\n", i, points [i].x, points [i].y);

		free (points);
	}
}